package org.dylan.security.shiro.realm;

import java.io.Serializable;
import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.dylan.security.entity.IPermission;
import org.dylan.security.entity.IRole;
import org.dylan.security.entity.IUser;
import org.dylan.security.service.PasswordService;
import org.dylan.security.service.SecurityService;

/**
 * 自定义的授权校验realm
 * 
 * @author dylan
 * 
 */
public class SecurityRealm extends AuthorizingRealm {
	public SecurityRealm() {
		passwordService = new PasswordService();
	}

	/**
	 * 
	 */
	private PasswordService passwordService;
	private SecurityService securityService;

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		IUser user = securityService.findByUsername(token.getUsername());
		if (user != null) {
			Hash hashedPassword = passwordService.parseHashedPassword(user
					.getPassword());
			return new SimpleAuthenticationInfo(new Principal(user),
					hashedPassword.getBytes(), hashedPassword.getSalt(),
					getName());
		} else {
			return null;
		}
	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		Principal principal = (Principal) getAvailablePrincipal(principals);
		IUser user = securityService.findByUsername(principal.getUsername());
		if (user != null) {
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			List<IRole> roleList = user.getRoles();
			for (IRole role : roleList) {
				List<IPermission> permList = role.getPermissions();
				for (IPermission permission : permList) {
					if (StringUtils.isNotBlank(permission.getPermission())) {
						// 添加基于Permission的权限信息
						info.addStringPermission(permission.getPermission());
					}
				}
			}
			return info;
		} else {
			return null;
		}
	}

	@Override
	protected void doClearCache(PrincipalCollection principals) {
		super.doClearCache(principals);
	}

	/**
	 * 设定密码校验的Hash算法与迭代次数
	 */
	@PostConstruct
	public void initCredentialsMatcher() {
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(
				passwordService.getAlgorithmName());
		matcher.setHashIterations(passwordService.getHashIterations());
		setCredentialsMatcher(matcher);
	}

	@Override
	public CredentialsMatcher getCredentialsMatcher() {
		return super.getCredentialsMatcher();
	}

	public PasswordService getPasswordService() {
		return passwordService;
	}

	public void setPasswordService(PasswordService passwordService) {
		this.passwordService = passwordService;
	}

	public SecurityService getSecurityService() {
		return securityService;
	}

	public void setSecurityService(SecurityService securityService) {
		this.securityService = securityService;
	}

	/**
	 * 授权用户信息
	 */
	public static class Principal implements Serializable {

		private static final long serialVersionUID = 1L;

		private String id;
		private String username;
		private String displayName;
		private IUser user;

		public Principal(IUser user) {
			this.id = user.getId();
			this.username = user.getUsername();
			this.displayName = user.getFullName();
			this.user = user;
		}

		public String getId() {
			return id;
		}

		public String getUsername() {
			return username;
		}

		public String getDisplayName() {
			return displayName;
		}

		public IUser getUser() {
			return user;
		}

		/**
		 * 用于标签的显示输出
		 */
		@Override
		public String toString() {
			return displayName;
		}

	}

}
